#include "m_epoll.h"
#include "nty_tree.h"

/** 产生回调的时机
 *  1. tcp 三次握手，对端反馈 ack 后， socket 进入 rcvd 状态，需要将监听 socket 的 event 置为 EPOLLIN，此时标识可以进入到 accept 读取 socket 数据
 *  2. 在 established 状态，收到数据以后，需要将 socket 的 event 置为 EPOLLIN 状态
 *  3. 在 established 状态，收到 fin 时，此时 socket 进入到 close_wait。需要 socket 的 event 置为 EPOLLIN。 读取断开信息。
 *  4. 检测 socket 的 send 状态，如果对端 cwnd > 0 是可以发送的数据。需要将 socket 置为 EPOLLOUT。   <------------client调用
 * */
int epoll_event_cb(struct eventpoll * ep, int socket_fd, uint32_t event){
    struct epitem tmp;
    tmp.sockfd = socket_fd;
    struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep->rbr, &tmp);
    if (!epi) {
        printf("rbtree not exist\n");
        return -1;
    }
    if (epi->rdy) {
        epi->event.events |= event;
        return 1;
    }

    printf("epoll_event_callback --> %d\n", epi->sockfd);
    pthread_spin_lock(&ep->lock);
    epi->rdy = 1;
    LIST_INSERT_HEAD(&ep->rdlist, epi, rdlink);
    ep->rdnum ++;
    pthread_spin_unlock(&ep->lock);
    pthread_mutex_lock(&ep->cdmtx);
    pthread_cond_signal(&ep->cond);
    pthread_mutex_unlock(&ep->cdmtx);
    return 0;
}


/**
 *  epoll  红黑树，+ 就绪队列， 红黑树上节点串联得到就绪队列
 *
 * */

int sockfd_cmp(struct epitem *ep1, struct epitem *ep2) {  //节点对比
    if (ep1->sockfd < ep2->sockfd) return -1;
    else if (ep1->sockfd == ep2->sockfd) return 0;
    return 1;
}


RB_HEAD(_epoll_rb_socket, epitem);
RB_GENERATE_STATIC(_epoll_rb_socket, epitem, rbn, sockfd_cmp);



// 初始化 eventpoll， 并且加入到 tcp_table 中的 ep 里
int m_epoll_create(int size) {
    if (size <= 0) return -1;
    int epoll_fd = get_fd_frombitmap();  // epoll_fd <---> struct event_poll

    struct eventpoll *ep = (struct eventpoll*)ret_malloc("eventpoll", sizeof(struct eventpoll), 0);
    if (!ep) {
        set_fd_frombitmap(epoll_fd);
        return -1;
    }

    struct tcp_table * table = get_tcp_instance();
    table->ep = ep;

    ep->fd = epoll_fd;
    ep->rbcnt = 0;
    RB_INIT(&ep->rbr);
    LIST_INIT(&ep->rdlist);

    if (pthread_mutex_init(&ep->mtx, NULL)) {
        free(ep);
        set_fd_frombitmap(epoll_fd);
        return -2;
    }

    if (pthread_mutex_init(&ep->cdmtx, NULL)) {
        pthread_mutex_destroy(&ep->mtx);
        free(ep);
        set_fd_frombitmap(epoll_fd);
        return -2;
    }

    if (pthread_cond_init(&ep->cond, NULL)) {
        pthread_mutex_destroy(&ep->cdmtx);
        pthread_mutex_destroy(&ep->mtx);
        free(ep);
        set_fd_frombitmap(epoll_fd);
        return -2;
    }

    if (pthread_spin_init(&ep->lock, PTHREAD_PROCESS_SHARED)) {
        pthread_cond_destroy(&ep->cond);
        pthread_mutex_destroy(&ep->cdmtx);
        pthread_mutex_destroy(&ep->mtx);
        free(ep);

        set_fd_frombitmap(epoll_fd);
        return -2;
    }
    return epoll_fd;
}

// 通过 fd 找到对应的eventpoll
int m_epoll_ctl(int epfd, int op, int sockid, struct epoll_event * ev){
    struct eventpoll * ep = (struct eventpoll *) get_host_info_from_fd(epfd);
    if(!ep || (!ev && op != EPOLL_CTL_DEL)) {
        rte_errno = -EINVAL;
        return -1;
    }
    if (op == EPOLL_CTL_ADD) {
        pthread_mutex_lock(&ep->mtx);
        struct epitem tmp;
        tmp.sockfd = sockid;
        struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep->rbr, &tmp);
        if (epi) {  // 如果有返回-1
            nty_trace_epoll("rbtree is exist\n");
            pthread_mutex_unlock(&ep->mtx);
            return -1;
        }
        // 没有分配一个加入到红黑树中
        epi = (struct epitem*)rte_malloc("epitem", sizeof(struct epitem), 0);
        if (!epi) {
            pthread_mutex_unlock(&ep->mtx);
            rte_errno = -ENOMEM;
            return -1;
        }

        epi->sockfd = sockid;
        memcpy(&epi->event, event, sizeof(struct epoll_event));

        epi = RB_INSERT(_epoll_rb_socket, &ep->rbr, epi);
        ep->rbcnt ++;  // 红黑树节点数量 +1
        pthread_mutex_unlock(&ep->mtx);
    } else if (op == EPOLL_CTL_DEL) {
        pthread_mutex_lock(&ep->mtx);
        struct epitem tmp;
        tmp.sockfd = sockid;
        struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep->rbr, &tmp);
        if (!epi) {
            pthread_mutex_unlock(&ep->mtx);
            return -1;
        }
        epi = RB_REMOVE(_epoll_rb_socket, &ep->rbr, epi);
        if (!epi) {
            pthread_mutex_unlock(&ep->mtx);
            return -1;
        }
        ep->rbcnt --;
        free(epi);
        pthread_mutex_unlock(&ep->mtx);
    } else if (op == EPOLL_CTL_MOD) {
        struct epitem tmp;
        tmp.sockfd = sockid;
        struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep->rbr, &tmp);
        if (epi) {
            epi->event.events = event->events;
            epi->event.events |= EPOLLERR | EPOLLHUP;
        } else {
            rte_errno = -ENOENT;
            return -1;
        }
    }
    return 0;
}

// 从就绪队列带出来
int m_epoll_wait(int epfd, struct epoll_event * events, int max_events, int time_out){
    // 拷贝就绪队列到events， nready++
    struct eventpoll *ep = (struct eventpoll*) get_host_info_from_fd(epfd);  // 找到对应是哪个epoll
    if (!ep || !events || maxevents <= 0) {
        rte_errno = -EINVAL;
        return -1;
    }
    if (pthread_mutex_lock(&ep->cdmtx)) {
        if (rte_errno == EDEADLK) {
            printf("epoll lock blocked\n");
        }
    }

    while (ep->rdnum == 0 && timeout != 0) {  // 就绪队列没有节点， 没超时，阻塞
        ep->waiting = 1;
        if (timeout > 0) {
            struct timespec deadline;
            clock_gettime(CLOCK_REALTIME, &deadline);
            if (timeout >= 1000) {
                int sec;
                sec = timeout / 1000;
                deadline.tv_sec += sec;
                timeout -= sec * 1000;
            }
            deadline.tv_nsec += timeout * 1000000;
            if (deadline.tv_nsec >= 1000000000) {
                deadline.tv_sec++;
                deadline.tv_nsec -= 1000000000;
            }
            int ret = pthread_cond_timedwait(&ep->cond, &ep->cdmtx, &deadline);
            if (ret && ret != ETIMEDOUT) {
                printf("pthread_cond_timewait\n");
                pthread_mutex_unlock(&ep->cdmtx);
                return -1;
            }
            timeout = 0;
        } else if (timeout < 0) {
            int ret = pthread_cond_wait(&ep->cond, &ep->cdmtx);
            if (ret) {
                printf("pthread_cond_wait\n");
                pthread_mutex_unlock(&ep->cdmtx);
                return -1;
            }
        }
        ep->waiting = 0;
    }

    pthread_mutex_unlock(&ep->cdmtx);
    pthread_spin_lock(&ep->lock);
    int cnt = 0;
    int num = (ep->rdnum > maxevents ? maxevents : ep->rdnum);
    int i = 0;
    while (num != 0 && !LIST_EMPTY(&ep->rdlist)) { //EPOLLET
        struct epitem *epi = LIST_FIRST(&ep->rdlist);
        LIST_REMOVE(epi, rdlink);
        epi->rdy = 0;
        memcpy(&events[i++], &epi->event, sizeof(struct epoll_event));  // 加入到就绪队列
        num --;
        cnt ++;
        ep->rdnum --;
    }
    pthread_spin_unlock(&ep->lock);
    return cnt;
}
